"use strict";
(function(gloal) {
    function mergeOptions(defaultOptn_, customOptn_) {
        let options_ = JSON.parse(JSON.stringify(defaultOptn_));
        for (let opt_d in options_) {
            for (let opt in customOptn_) {
                if (opt_d == opt) {
                    options_[opt] = customOptn_[opt]
                }
            }
        }
        return options_
    }
    function turnPxWDTL(f_w, f_d, f_h, w, d, h, lf, tp, rt, bt, ofZ, optn) {
        if (w && w.includes("%")) {
            let percent_ = parseFloat(w);
            w = percent_ / 100 * f_w + "px"
        }
        if (d && d.includes("%")) {
            let percent_ = parseFloat(d);
            d = percent_ / 100 * f_d + "px"
        }
        if (h && h.includes("%")) {
            let percent_ = parseFloat(h);
            h = percent_ / 100 * f_h + "px"
        }
        if (lf && lf !== "auto") {
            lf = lf.includes("%") ? parseFloat(lf) / 100 * f_w + "px" : lf
        } else {
            if (rt && rt !== "auto") {
                lf = rt.includes("%") ? f_w - parseFloat(rt) / 100 * f_w - parseFloat(w) + "px" : f_w - parseFloat(rt) - parseFloat(w) + "px"
            } else {
                lf = "0px"
            }
        }
        if (tp && tp !== "auto") {
            tp = tp.includes("%") ? parseFloat(tp) / 100 * f_d + "px" : tp
        } else {
            if (bt && bt !== "auto") {
                tp = bt.includes("%") ? f_d - parseFloat(bt) / 100 * f_d - parseFloat(d) + "px" : f_d - parseFloat(bt) - parseFloat(d) + "px"
            } else {
                tp = "0px"
            }
        }
        if (ofZ) {
            if (ofZ !== "auto") {
                ofZ = ofZ.includes("%") ? parseFloat(ofZ) / 100 * f_h + "px" : ofZ
            } else {
                ofZ = "0px"
            }
        }
        optn.width = w;
        optn.depth = d;
        optn.left = lf;
        optn.top = tp;
        if (ofZ) {
            optn.offsetZ = ofZ
        }
        if (h) {
            optn.height = h
        }
        return {
            w: w,
            d: d,
            h: h,
            lf: lf,
            tp: tp,
            ofZ: ofZ
        }
    }
    function toHtmlList(string_) {
        let list = document.createElement("div")
          , doms = [];
        list.innerHTML = string_;
        for (let i = 0; i < list.children.length; i++) {
            doms.push(list.children[i])
        }
        return doms
    }
    function showElement(target_, boolean_) {
        if (target_.length) {
            for (let i = 0; i < target_.length; i++) {
                target_[i].style.visibility = boolean_ ? "visible" : "hidden"
            }
        } else {
            target_.style.visibility = boolean_ ? "visible" : "hidden"
        }
    }
    function faceMe(Rv, Rh, target_) {
        let t = Math.PI / 180, V0, V8, V9;
        let rotateX_, rotateY_, rotateZ_, mirrorY_;
        V0 = Math.cos(parseFloat(Rh) * t);
        if (Math.cos(parseFloat(Rv) * t) > 0) {
            V8 = Math.sin(parseFloat(Rv) * t) * Math.sin(parseFloat(Rh) * t);
            V9 = Math.sin(parseFloat(Rv) * t) * Math.cos(parseFloat(Rh) * t);
            mirrorY_ = 1
        } else {
            V8 = -Math.sin(parseFloat(Rv) * t) * Math.sin(parseFloat(Rh) * t);
            V9 = -Math.sin(parseFloat(Rv) * t) * Math.cos(parseFloat(Rh) * t);
            mirrorY_ = -1
        }
        rotateX_ = Math.asin(-parseFloat(V9) / Math.cos(Math.asin(parseFloat(V8)))) / t;
        rotateY_ = Math.asin(parseFloat(V8)) / t;
        rotateZ_ = Math.sin(parseFloat(Rh) * t) > 0 ? -Math.acos(parseFloat(V0) / Math.cos(Math.asin(parseFloat(V8)))) / t : Math.acos(parseFloat(V0) / Math.cos(Math.asin(parseFloat(V8)))) / t;
        target_.style.transform = "rotateX(" + rotateX_ + "deg) rotateY(" + rotateY_ + "deg) rotateZ(" + rotateZ_ + "deg)  translateY(" + 50 * -mirrorY_ + "%) scaleY(" + mirrorY_ + ")"
    }
    function replaceParams(box, str, params) {
        if (params.title == undefined) {
            params.title = box.options.name || "Marker"
        }
        let reg = /{{params\.([a-zA-Z]+[0-9]*\_*[a-zA-Z]*[0-9]*)}}/g
          , str_new = str.replace(reg, function(r_, key) {
            return params[key]
        });
        return str_new
    }
    function markerLineRotate(line_, markerOption_, boxOption_, roomOption_) {
        let line_V = parseFloat(markerOption_.offsetZ) - parseFloat(boxOption_.height) - parseFloat(boxOption_.offsetZ)
          , line_L = parseFloat(markerOption_.left) - parseFloat(roomOption_.left) - parseFloat(boxOption_.left) - parseFloat(boxOption_.width) / 2
          , line_T = parseFloat(markerOption_.top) - parseFloat(roomOption_.top) - parseFloat(boxOption_.top) - parseFloat(boxOption_.depth) / 2
          , line_H = Math.sqrt(Math.pow(line_L, 2) + Math.pow(line_T, 2))
          , line_width = Math.sqrt(Math.pow(line_V, 2) + Math.pow(line_H, 2)) + "px";
        line_.style.width = line_width;
        let rotate_Z, rotate_Y;
        rotate_Z = line_L == 0 ? 90 : line_L > 0 ? Math.atan(line_T / line_L) * 180 / Math.PI - 180 : Math.atan(line_T / line_L) * 180 / Math.PI;
        rotate_Y = line_V >= 0 ? 90 - Math.atan(line_H / line_V) * 180 / Math.PI : 360 - 90 - Math.atan(line_H / line_V) * 180 / Math.PI;
        line_.style.transform = "rotateZ(" + rotate_Z + "deg) rotateY(" + rotate_Y + "deg) "
    }
    function Scene3D(wraper_, options_) {
        let this_ = this;
        const optionsDefault = {
            width: "1000px",
            depth: "1000px",
            offsetVer: "-200px",
            rotateVer: "70deg",
            rotateHor: "-40deg",
            scaleRat: .8,
            wheelScale: true,
            showGrid: true,
            perspective: 2e3,
            dragRotate: true,
            rotateFixed: "aroundRestric",
            rooms: []
        };
        this_.options = mergeOptions(optionsDefault, options_);
        let sOptions = this_.options;
        if (sOptions.width.includes("%") || sOptions.depth.includes("%")) {
            console.error("The value of Scene width and depth can not be percentage");
            console.error("场景的宽度值和进深不能使用百分比");
            return
        }
        this_.scene = document.querySelector(wraper_);
        this_.sceneWraper = document.createElement("div");
        this_.sceneGround = document.createElement("div");
        this_.sceneGrid = document.createElement("div");
        let scene = this_.scene
          , sceneWraper = this_.sceneWraper
          , sceneGround = this_.sceneGround
          , sceneGrid = this_.sceneGrid;
        scene.classList.add("Scene3D");
        sceneWraper.classList.add("Scene3D_Wraper");
        sceneGround.classList.add("Scene3D_Ground");
        sceneGrid.classList.add("Scene3D_Grid");
        sceneWraper.style.width = sOptions.width;
        sceneWraper.style.height = sOptions.depth;
        sceneWraper.style.marginLeft = -parseFloat(sOptions.width) / 2 + "px";
        sceneWraper.style.marginTop = -parseFloat(sOptions.depth) / 2 + "px";
        sceneWraper.style["-moz-perspective"] = sOptions.perspective + "px";
        sceneWraper.style["-webkit-perspective"] = sOptions.perspective + "px";
        sceneWraper.style.perspective = sOptions.perspective + "px";
        sceneWraper.style.transform = "scale(" + sOptions.scaleRat + ")";
        sceneGround.style.transform = "rotateX(" + sOptions.rotateVer + ") rotateY(0deg) rotateZ(" + sOptions.rotateHor + ")";
        sceneGround.style.top = -parseFloat(sOptions.offsetVer) + "px";
        sceneGround.appendChild(sceneGrid);
        sceneWraper.appendChild(sceneGround);
        scene.appendChild(sceneWraper);
        for (let i = 0, l = 30; i <= l; i++) {
            let gridW = sceneGrid.offsetWidth
              , gridH = sceneGrid.offsetHeight
              , space_W = i * gridW / l
              , space_H = i * gridH / l
              , hr = '<hr class="sceneGrid SceneGrid_H" style="top:' + space_H + 'px"/><hr class="sceneGrid SceneGrid_V" style="left:' + space_W + 'px"/>';
            sceneGrid.innerHTML += hr
        }
        this_.showGrid(sOptions.showGrid);
        scene.ondragstart = function() {
            return false
        }
        ;
        let dragStatus = false, regH = /rotateZ\((\-*\d+\.*\d*)deg\)/g, regV = /rotateX\((\-*\d+\.*\d*)deg\)/g, moveStartH, moveStartV, rotateH, rotateV, rotateH_marker, rotateV_marker;
        scene.addEventListener("mousedown", function(e) {
            if (sOptions.dragRotate) {
                dragStatus = true;
                moveStartH = e.clientX;
                moveStartV = e.clientY;
                let transform_ = sceneGround.style.transform;
                transform_.replace(regH, function(_, value) {
                    rotateH = Number(value)
                });
                transform_.replace(regV, function(_, value) {
                    rotateV = Number(value)
                })
            }
        });
        document.addEventListener("mousemove", function(e) {
            if (dragStatus && sOptions.dragRotate) {
                let moveH, moveV, rotateX_new, rotateY_new;
                switch (sOptions.rotateFixed) {
                case "around":
                    {
                        moveH = moveStartH - e.clientX;
                        moveV = moveStartV - e.clientY;
                        rotateX_new = +(rotateV + moveV / 10).toFixed(2);
                        rotateY_new = +(rotateH + moveH / 10).toFixed(2)
                    }
                    ;break;
                case "aroundRestric":
                    {
                        moveH = moveStartH - e.clientX;
                        moveV = moveStartV - e.clientY;
                        rotateX_new = +(rotateV + moveV / 10).toFixed(2);
                        rotateY_new = +(rotateH + moveH / 10).toFixed(2);
                        if (rotateX_new < 0) {
                            rotateX_new = 0
                        }
                        if (rotateX_new > 90) {
                            rotateX_new = 90
                        }
                    }
                    ;break;
                case "horizontal":
                    {
                        moveH = moveStartH - e.clientX;
                        rotateX_new = rotateV;
                        rotateY_new = +(rotateH + moveH / 10).toFixed(2)
                    }
                    ;break;
                case "vertical":
                    {
                        moveV = moveStartV - e.clientY;
                        rotateX_new = +(rotateV + moveV / 10).toFixed(2);
                        rotateY_new = rotateH
                    }
                    ;break;
                case "verticalRestric":
                    {
                        moveV = moveStartV - e.clientY;
                        rotateX_new = +(rotateV + moveV / 10).toFixed(2);
                        rotateY_new = rotateH;
                        if (rotateX_new < 0) {
                            rotateX_new = 0
                        }
                        if (rotateX_new > 90) {
                            rotateX_new = 90
                        }
                    }
                    ;break
                }
                sceneGround.style.transform = "rotateX(" + rotateX_new + "deg) rotateY(0deg) rotateZ(" + rotateY_new + "deg)";
                rotateH_marker = rotateY_new;
                rotateV_marker = rotateX_new;
                for (let i = 0; i < this_.markers.length; i++) {
                    faceMe(rotateV_marker, rotateH_marker, this_.markers[i].wraper.firstElementChild)
                }
            }
        });
        document.addEventListener("mouseup", function(e) {
            if (sOptions.dragRotate) {
                dragStatus = false
            }
        });
        let scale_wheel = sOptions.scaleRat;
        scene.addEventListener("wheel", function(e) {
            if (sOptions.wheelScale) {
                console.log('缩放比1:',scale_wheel)
                if (e.wheelDelta > 0) {
                    scale_wheel = scale_wheel < 5.2 ? 1.1 * scale_wheel : scale_wheel
                }
                if (e.wheelDelta < 0) {
                    scale_wheel = scale_wheel > .08 ? .9 * scale_wheel : scale_wheel
                }
                console.log('缩放比:',scale_wheel)
                sceneWraper.style.transform = "scale(" + scale_wheel + ")"
            }
        });
        this.markers = [];
        this_.rooms = [];
        for (let i = 0; i < sOptions.rooms.length; i++) {
            let room = new Room3D(sceneGround,sOptions.rooms[i],this_);
            this_.rooms.push(room)
        }
        return this
    }
    Scene3D.prototype = {
        showGrid(boolean_) {
            showElement(this.sceneGrid, boolean_);
            return this
        },
        buildRoom(options) {
            let room = new Room3D(this.sceneGround,options,this);
            return room
        },
        resetScene() {
            this.sceneWraper.style.transform = "scale(" + this.options.scaleRat + ")";
            this.sceneGround.style.transform = "rotateX(" + this.options.rotateVer + ") rotateY(0deg) rotateZ(" + this.options.rotateHor + ")";
            for (let i = 0; i < this.markers.length; i++) {
                faceMe(this.options.rotateVer, this.options.rotateHor, this.markers[i].wraper.firstElementChild)
            }
            return this
        }
    };
    function Room3D(scene_, roomOpt_, father_) {
        let room_this_ = this;
        let roomDefaultOptn = {
            className: "",
            width: "100%",
            depth: "100%",
            height: "300px",
            left: "auto",
            top: "auto",
            right: "auto",
            bottom: "auto",
            showWall: true,
            wallColor: "#ddd",
            wallOpacity: .9,
            wallBackFace: "hidden",
            showLine: true,
            lineColor: "#666",
            lineOpacity: 1,
            lineWidth: "1px",
            showFloor: true,
            floorColor: "#444",
            floorOpacity: 1,
            boxes: []
        };
        room_this_.options = mergeOptions(roomDefaultOptn, roomOpt_);
        let rOptions = room_this_.options;
        let f_w = parseFloat(father_.options.width)
          , f_d = parseFloat(father_.options.depth);
        if (rOptions.height.includes("%")) {
            console.error("The value of Room height can not be percentage");
            console.error("房间的高度值不能使用百分比");
            return
        }
        turnPxWDTL(f_w, f_d, undefined, rOptions.width, rOptions.depth, undefined, rOptions.left, rOptions.top, rOptions.right, rOptions.bottom, undefined, rOptions);
        room_this_.roomWraper = document.createElement("div");
        let room = room_this_.roomWraper;
        room.classList.add("Room3D_room", "Room3D_room_" + rOptions.className);
        room.style.width = rOptions.width;
        room.style.height = rOptions.depth;
        room.style.left = rOptions.left;
        room.style.top = rOptions.top;
        room_this_.floor = document.createElement("div");
        room_this_.floor.classList.add("Room3D_floor");
        room_this_.floor.style.background = rOptions.floorColor;
        room_this_.floor.style.opacity = rOptions.floorOpacity;
        room.appendChild(room_this_.floor);
        room_this_.showFloor(rOptions.showFloor);
        room_this_.walls = {
            back: {},
            right: {},
            fore: {},
            left: {}
        };
        for (let wall_ in room_this_.walls) {
            let Ws = room_this_.walls;
            let wall_wrap = document.createElement("div");
            wall_wrap.classList.add("Room3D_wall", "Room3D_wall_" + wall_);
            wall_wrap.innerHTML = '<div class="Room3D_wall_main"><span></span></div>';
            Ws[wall_].dom = wall_wrap;
            Ws[wall_].height = rOptions.height;
            switch (wall_) {
            case "back":
            case "fore":
                {
                    Ws[wall_].width = Ws[wall_].dom.style.width = rOptions.width
                }
                ;break;
            case "left":
            case "right":
                {
                    Ws[wall_].width = Ws[wall_].dom.style.width = rOptions.depth
                }
                ;break
            }
            Ws[wall_].dom.firstElementChild.style.height = rOptions.height;
            Ws[wall_].dom.firstElementChild.firstElementChild.style.background = rOptions.wallColor;
            Ws[wall_].dom.firstElementChild.firstElementChild.style.opacity = rOptions.wallOpacity;
            room.appendChild(Ws[wall_].dom);
            Ws[wall_].doors = []
        }
        room_this_.showWall(rOptions.showWall);
        room_this_.backface(rOptions.wallBackFace);
        room_this_.cornerlines = toHtmlList(`<span class="Room3D_line Room3D_line_left_hori"><span></span></span><span class="Room3D_line Room3D_line_fore_hori"><span></span></span><span class="Room3D_line Room3D_line_right_hori"><span></span></span><span class="Room3D_line Room3D_line_back_hori"><span></span></span><span class="Room3D_line Room3D_line_left_vert"><span></span></span><span class="Room3D_line Room3D_line_fore_vert"><span></span></span><span class="Room3D_line Room3D_line_right_vert"><span></span></span><span class="Room3D_line Room3D_line_back_vert"><span></span></span>`);
        for (let i = 0; i < room_this_.cornerlines.length; i++) {
            if (room_this_.cornerlines[i].className.includes("_hori")) {
                room_this_.cornerlines[i].style.transform = "translateZ(" + rOptions.height + ")"
            } else {
                room_this_.cornerlines[i].style.width = rOptions.height
            }
            if (room_this_.cornerlines[i].className.includes("_left_hori") || room_this_.cornerlines[i].className.includes("_right_hori")) {
                room_this_.cornerlines[i].style.width = rOptions.lineWidth;
                room_this_.cornerlines[i].style.borderLeftWidth = rOptions.lineWidth;
                room_this_.cornerlines[i].firstElementChild.style.left = "-" + rOptions.lineWidth;
                room_this_.cornerlines[i].firstElementChild.style.borderLeftWidth = rOptions.lineWidth
            }
            if (room_this_.cornerlines[i].className.includes("_fore_hori") || room_this_.cornerlines[i].className.includes("_back_hori") || room_this_.cornerlines[i].className.includes("_vert")) {
                room_this_.cornerlines[i].style.height = rOptions.lineWidth;
                room_this_.cornerlines[i].style.borderTopWidth = rOptions.lineWidth;
                room_this_.cornerlines[i].firstElementChild.style.top = "-" + rOptions.lineWidth;
                room_this_.cornerlines[i].firstElementChild.style.borderTopWidth = rOptions.lineWidth
            }
            room_this_.cornerlines[i].style.borderColor = rOptions.lineColor;
            room_this_.cornerlines[i].style.opacity = rOptions.lineOpacity;
            room_this_.cornerlines[i].firstElementChild.style.borderColor = rOptions.lineColor;
            room.appendChild(room_this_.cornerlines[i])
        }
        room_this_.showLine(rOptions.showLine);
        scene_.appendChild(room);
        room_this_.father = father_;
        room_this_.boxes = [];
        for (let i = 0; i < rOptions.boxes.length; i++) {
            let box = new Box3D(room,rOptions.boxes[i],room_this_);
            room_this_.boxes.push(box)
        }
        return this
    }
    Room3D.prototype = {
        showFloor(boolean_) {
            showElement(this.floor, boolean_);
            return this
        },
        showWall(boolean_) {
            for (let w in this.walls) {
                showElement(this.walls[w].dom.firstElementChild, boolean_)
            }
            return this
        },
        showLine(boolean_) {
            showElement(this.cornerlines, boolean_);
            return this
        },
        backface(value) {
            for (let w in this.walls) {
                this.walls[w].dom.firstElementChild.style.backfaceVisibility = value
            }
            return this
        },
        buildBox(options) {
            let box = new Box3D(this.roomWraper,options,this);
            return box
        },
        buildDoor(wall, doorOptions) {
            let doorObj = new Object;
            let Wall = this.walls[wall];
            let doorDefaultOptions = {
                className: "",
                width: "60px",
                height: "120px",
                left: "50%",
                right: "auto",
                show: true,
                type: "single left",
                openSide: "outside",
                color: "#634A42",
                doorFrameWidth: "3px",
                doorFrameColor: "#3B2A24"
            };
            doorObj.options = mergeOptions(doorDefaultOptions, doorOptions);
            let dOptions = doorObj.options;
            let w_ = parseFloat(Wall.width)
              , h_ = parseFloat(Wall.height);
            turnPxWDTL(w_, undefined, h_, dOptions.width, undefined, dOptions.height, dOptions.left, undefined, dOptions.right, undefined, undefined, dOptions);
            let canvas = document.createElement("canvas")
              , ctx = canvas.getContext("2d");
            canvas.width = w_;
            canvas.height = h_;
            ctx.fillStyle = "#ffffff";
            ctx.fillRect(0, 0, w_, h_);
            if (Wall.doors) {
                for (let i = 0; i < Wall.doors.length; i++) {
                    let door_lf = parseFloat(Wall.doors[i].options.left)
                      , door_tp = parseFloat(Wall.doors[i].options.top)
                      , door_w = parseFloat(Wall.doors[i].options.width)
                      , door_h = parseFloat(Wall.doors[i].options.height);
                    ctx.clearRect(door_lf, door_tp, door_w, door_h)
                }
            }
            dOptions.left = dOptions.left !== undefined ? dOptions.left : w_ - parseFloat(dOptions.width) - parseFloat(dOptions.right) + "px";
            dOptions.top = h_ - parseFloat(dOptions.height) + "px";
            ctx.clearRect(parseFloat(dOptions.left), parseFloat(dOptions.top), parseFloat(dOptions.width), parseFloat(dOptions.height));
            let doorWrap = document.createElement("div");
            doorWrap.classList.add("Room3D_door", "Room3D_door_" + dOptions.className, "Room3D_door_" + dOptions.openSide);
            doorWrap.style.width = dOptions.width;
            doorWrap.style.height = dOptions.height;
            doorWrap.style.left = dOptions.left;
            doorWrap.style.border = "solid " + dOptions.doorFrameWidth + " " + dOptions.doorFrameColor;
            if (dOptions.type.includes("single")) {
                doorWrap.innerHTML = '<div class="Room3D_door_single"></div>';
                doorWrap.firstElementChild.style.background = dOptions.color;
                doorWrap.firstElementChild.style.transformOrigin = dOptions.type.includes("left") ? "left center 0" : "right center 0";
                if (dOptions.type.includes("left")) {
                    doorWrap.firstElementChild.classList.add("Room3D_door_left")
                } else {
                    doorWrap.firstElementChild.classList.add("Room3D_door_right")
                }
            } else if (dOptions.type.includes("double")) {
                doorWrap.innerHTML = '<div class="Room3D_door_double Room3D_door_double_lf"></div><div class="Room3D_door_double Room3D_door_double_rt"></div>';
                for (let i = 0; i < doorWrap.children.length; i++) {
                    doorWrap.children[i].style.background = dOptions.color
                }
            }
            showElement(doorWrap, dOptions.show);
            doorObj.wraper = doorWrap;
            doorObj.openDoor = function() {
                this.wraper.classList.add("Room3D_door_open")
            }
            ;
            doorObj.closeDoor = function() {
                this.wraper.classList.remove("Room3D_door_open")
            }
            ;
            Wall.doors.push(doorObj);
            Wall.dom.appendChild(doorWrap);
            let img = canvas.toDataURL("image/png", .1);
            Wall.dom.firstElementChild.firstElementChild.style.webkitMaskImage = "url(" + img + ")";
            return doorObj
        },
        destroy() {
            for (let i = 0; i < this.boxes.length; i++) {
                this.boxes[i].destroy()
            }
            this.boxes = null;
            let index = this.father.rooms.indexOf(this);
            this.father.rooms.splice(index);
            this.father.sceneGround.removeChild(this.roomWraper);
            this.roomWraper = null;
            this.father = null;
            this.cornerlines = null;
            this.floor = null;
            this.options = null;
            this.walls = null
        }
    };
    function Box3D(room_, boxOpt_, father_) {
        let box_this_ = this;
        let boxDefaultOptn = {
            className: "",
            name: "",
            width: "100%",
            depth: "100%",
            height: "100%",
            left: "auto",
            top: "auto",
            right: "auto",
            bottom: "auto",
            offsetZ: "auto",
            rotateX: "0deg",
            rotateY: "0deg",
            rotateZ: "0deg",
            opacity: 1,
            color: "#999",
            showLine: true,
            lineColor: "#666",
            lineOpacity: 1,
            lineWidth: "1px",
            marker: {}
        };
        box_this_.options = mergeOptions(boxDefaultOptn, boxOpt_);
        let bOptions = box_this_.options;
        let f_w = parseFloat(father_.options.width)
          , f_d = parseFloat(father_.options.depth)
          , f_h = parseFloat(father_.options.height);
        turnPxWDTL(f_w, f_d, f_h, bOptions.width, bOptions.depth, bOptions.height, bOptions.left, bOptions.top, bOptions.right, bOptions.bottom, bOptions.offsetZ, bOptions);
        box_this_.boxWraper = document.createElement("div");
        let box = box_this_.boxWraper;
        box.classList.add("Box3D_box", "Box3D_box_" + bOptions.className);
        box.style.width = bOptions.width;
        box.style.height = bOptions.depth;
        box.style.left = bOptions.left;
        box.style.top = bOptions.top;
        box.style.transform = "translateZ(" + bOptions.offsetZ + ") rotateX(" + bOptions.rotateX + ") rotateY(" + bOptions.rotateY + ") rotateZ(" + bOptions.rotateZ + ")";
        box_this_.cornerlines = [];
        box_this_.sides = toHtmlList(`<div class="Box3D_side Box3D_bottom"><div><span></span></div></div><div class="Box3D_side Box3D_left"><div><span></span></div></div><div class="Box3D_side Box3D_right"><div><span></span></div></div><div class="Box3D_side Box3D_fore"><div><span></span></div></div><div class="Box3D_side Box3D_back"><div><span></span></div></div><div class="Box3D_side Box3D_top"><div><span></span></div></div>`);
        for (let i = 0; i < box_this_.sides.length; i++) {
            if (box_this_.sides[i].className.includes("Box3D_left") || box_this_.sides[i].className.includes("Box3D_right")) {
                box_this_.sides[i].style.width = bOptions.height
            } else if (box_this_.sides[i].className.includes("Box3D_fore") || box_this_.sides[i].className.includes("Box3D_back")) {
                box_this_.sides[i].style.height = bOptions.height
            } else if (box_this_.sides[i].className.includes("Box3D_top")) {
                box_this_.sides[i].style.transform = "translateZ(" + bOptions.height + ")"
            }
            box_this_.sides[i].style.background = bOptions.color;
            box_this_.sides[i].style.opacity = bOptions.opacity;
            box_this_.sides[i].firstElementChild.firstElementChild.style.borderColor = bOptions.lineColor;
            box_this_.sides[i].firstElementChild.firstElementChild.style.opacity = bOptions.lineOpacity;
            box_this_.sides[i].firstElementChild.firstElementChild.style.borderWidth = bOptions.lineWidth;
            box_this_.cornerlines.push(box_this_.sides[i].firstElementChild.firstElementChild);
            box.appendChild(box_this_.sides[i])
        }
        box_this_.showLine(bOptions.showLine);
        room_.appendChild(box);
        box_this_.father = father_;
        box_this_.marker = new Marker3D(this.father.father,this,bOptions.marker);
        return this
    }
    Box3D.prototype = {
        showLine(boolean_) {
            showElement(this.cornerlines, boolean_);
            return this
        },
        showMarker(boolean_) {
            showElement(this.marker.wraper, boolean_);
            return this
        },
        buildMarker(options) {
            this.marker.destroy();
            let marker = new Marker3D(this.father.father,this,options);
            return marker
        },
        destroy() {
            this.marker.destroy();
            let index = this.father.boxes.indexOf(this);
            this.father.boxes.splice(index);
            this.father.roomWraper.removeChild(this.boxWraper);
            this.boxWraper = null;
            this.father = null;
            this.options = null
        }
    };
    function Marker3D(scene, box, options) {
        scene.markers.push(this);
        box.marker = this;
        this.box = box;
        this.scene = scene;
        let marker_this = this;
        let defaultOptions = {
            left: parseFloat(box.options.left) + parseFloat(box.father.options.left) + parseFloat(box.options.width) / 2 + "px",
            right: "auto",
            top: parseFloat(box.options.top) + parseFloat(box.father.options.top) + parseFloat(box.options.depth) / 2 + "px",
            bottom: "auto",
            width: "auto",
            height: "auto",
            content: "<h4>{{params.title}}</h4>",
            lineColor: "#666",
            lineWidth: "1px",
            fontSize: "14px",
            fontColor: "#ffffff",
            backgroundColor: "rgba(36, 212, 174, 0.9)",
            show: true,
            offsetZ: parseFloat(box.father.options.height) * 1.2 + "px",
            params: {
                title: box.options.name || "Marker"
            }
        };
        marker_this.options = mergeOptions(defaultOptions, options);
        let mOptions = marker_this.options;
        let f_w = parseFloat(marker_this.scene.options.width)
          , f_d = parseFloat(marker_this.scene.options.depth)
          , f_h = parseFloat(box.father.options.height);
        turnPxWDTL(f_w, f_d, f_h, mOptions.width, undefined, mOptions.height, mOptions.left, mOptions.top, mOptions.right, mOptions.bottom, mOptions.offsetZ, mOptions);
        let marker = document.createElement("div");
        marker_this.wraper = marker;
        marker.classList.add("Marker3D_marker", "Marker3D_marker_" + box.options.className);
        marker.style.left = mOptions.left;
        marker.style.top = mOptions.top;
        marker.style.transform = "translateX(-50%)  translateY(-50%) translateZ(" + mOptions.offsetZ + ")";
        let content = document.createElement("div");
        marker_this.content = content;
        content.classList.add("Marker3D_content");
        content.style.width = mOptions.width;
        content.style.height = mOptions.height;
        content.style.fontSize = mOptions.fontSize;
        content.style.color = mOptions.fontColor;
        content.style.backgroundColor = mOptions.backgroundColor;
        content.innerHTML = replaceParams(marker_this.box, mOptions.content, mOptions.params);
        faceMe(marker_this.scene.options.rotateVer, marker_this.scene.options.rotateHor, content);
        let line = document.createElement("div");
        line.classList.add("Marker3D_line");
        line.innerHTML = "<span></span>";
        markerLineRotate(line, mOptions, box.options, box.father.options);
        line.style.background = "linear-gradient(to right, " + mOptions.lineColor + ", transparent)";
        line.style.height = mOptions.lineWidth;
        line.firstElementChild.style.background = "linear-gradient(to right, " + mOptions.lineColor + ", transparent)";
        marker.appendChild(content);
        marker.appendChild(line);
        marker_this.scene.sceneGround.appendChild(marker);
        marker.style.display = mOptions.show ? "block" : "none";
        return this
    }
    Marker3D.prototype = {
        destroy() {
            let index = this.scene.markers.indexOf(this);
            this.scene.markers.splice(index);
            this.box.marker = null;
            this.scene.sceneGround.removeChild(this.wraper);
            this.wraper = null;
            this.box = null;
            this.scene = null;
            this.options = null
        },
        updateMarker(params) {
            this.content.innerHTML = replaceParams(this.box, this.options.content, params);
            return this
        }
    };
    gloal.Scene3D = Scene3D
}
)(this);
if (typeof module !== "undefined") {
    module.exports = this.Scene3D
} else if (typeof define === "function" && define.amd) {
    define([], function() {
        "use strict";
        return this.Scene3D
    })
}
